/*
 * Copyright 2019 xiaomaoguai.com All right reserved. This software is the
 * confidential and proprietary information of xiaomaoguai.com ("Confidential
 * Information"). You shall not disclose such Confidential Information and shall
 * use it only in accordance with the terms of the license agreement you entered
 * into with xiaomaoguai.com.
 */

package com.xiaomaoguai.core.next.tddl.diamond;

import app.myoss.cloud.core.exception.BizRuntimeException;
import com.alibaba.fastjson.util.TypeUtils;
import com.taobao.diamond.client.Diamond;
import com.taobao.diamond.manager.ManagerListenerAdapter;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.InitializingBean;

import java.io.IOException;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.HashMap;
import java.util.Map;

/**
 * 订阅Diamond配置
 *
 * <pre>
 * <code>
 *  &#064;Bean
 *  public BizDiamondConfig testDiamond() {
 *      BizDiamondConfig diamondConfig = new BizDiamondConfig();
 *      diamondConfig.setDataID("com.xiaomaoguai.tom.test");
 *      diamondConfig.setGroupID("DEFAULT_GROUP");
 *      return diamondConfig;
 *  }
 * </code>
 * </pre>
 *
 * 使用：
 *
 * <pre>
 * <code>
 *  &#064;Autowired
 *  private BizDiamondConfig testDiamond;
 *
 *  public String getConfig() {
 *      String userName = testDiamond.getString("userName");
 *      String password = testDiamond.getString("password");
 *      return "userName: " + userName + ", password: " + password;
 *  }
 * </code>
 * </pre>
 *
 * @author chenyao
 * @since 2016年05月06日 下午2:53:24
 */
public class BizDiamondConfig implements InitializingBean {
    /**
     * 上下行之间的分隔符：<code>\r\n</code>
     */
    public static final String        DEFAULT_LINE_SEPARATOR      = "\r\n";
    /**
     * key/value之间的分隔符：<code>:</code>
     */
    public static final String        DEFAULT_KEY_VALUE_SEPARATOR = ":";
    /**
     * 默认的groupID：<code>DEFAULT_GROUP</code>
     */
    public static final String        DEFAULT_GROUP_ID            = "DEFAULT_GROUP";
    private String                    groupID                     = DEFAULT_GROUP_ID;
    private String                    dataID;
    private String                    lineSeparator               = DEFAULT_LINE_SEPARATOR;
    private String                    keyValueSeparator           = DEFAULT_KEY_VALUE_SEPARATOR;

    private final Map<String, String> configs                     = new HashMap<>();

    /**
     * 设置groupID
     *
     * @param groupID groupID
     */
    public void setGroupID(String groupID) {
        this.groupID = groupID;
    }

    /**
     * 设置dataID
     *
     * @param dataID dataID
     */
    public void setDataID(String dataID) {
        this.dataID = dataID;
    }

    /**
     * 设置上下行之间的分隔符，默认是 {@value DEFAULT_LINE_SEPARATOR}
     *
     * @param lineSeparator 上下行之间的分隔符
     */
    public void setLineSeparator(String lineSeparator) {
        this.lineSeparator = lineSeparator;
    }

    /**
     * 设置key/value之间的分隔符，默认是 {@value DEFAULT_KEY_VALUE_SEPARATOR}
     *
     * @param keyValueSeparator key/value之间的分隔符
     */
    public void setKeyValueSeparator(String keyValueSeparator) {
        this.keyValueSeparator = keyValueSeparator;
    }

    @Override
    public void afterPropertiesSet() {
        // 接收diamond消息
        try {
            resolveConfigInfo(Diamond.getConfig(this.dataID, this.groupID, 5000));
        } catch (IOException ex) {
            throw new BizRuntimeException("dataID=" + this.dataID + ", groupID=" + this.groupID, ex);
        }
        // 增加订阅事件
        Diamond.addListener(this.dataID, this.groupID, new ManagerListenerAdapter() {
            @Override
            public void receiveConfigInfo(String configInfo) {
                resolveConfigInfo(configInfo);
            }
        });
    }

    /**
     * 解析配置信息
     *
     * @param configInfo 配置内容（全量）
     */
    private void resolveConfigInfo(String configInfo) {
        String[] lines = StringUtils.defaultIfEmpty(configInfo, StringUtils.EMPTY).split(this.lineSeparator);
        for (String line : lines) {
            if (StringUtils.isBlank(line) || line.startsWith("#")) {
                continue;
            }
            String[] split = line.split(this.keyValueSeparator);
            if (split.length >= 2) {
                StringBuilder value = new StringBuilder(split[1]);
                for (int i = 2; i < split.length; i++) {
                    value.append(":").append(split[i]);
                }
                this.configs.put(split[0], value.toString());
            }
        }
    }

    /**
     * 根据 key 获取 value
     *
     * @param key key
     * @return value
     */
    public String getConfig(String key) {
        return this.configs.get(key);
    }

    /**
     * 根据 key 获取 value
     *
     * @param key key
     * @return value
     */
    public String getString(String key) {
        return getConfig(key);
    }

    /**
     * 根据 key 获取 value
     *
     * @param key key
     * @return value
     */
    public Boolean getBoolean(String key) {
        return TypeUtils.castToBoolean(getConfig(key));
    }

    /**
     * 根据 key 获取 value
     *
     * @param key key
     * @return value
     */
    public Integer getInteger(String key) {
        return TypeUtils.castToInt(getConfig(key));
    }

    /**
     * 根据 key 获取 value
     *
     * @param key key
     * @return value
     */
    public Long getLong(String key) {
        return TypeUtils.castToLong(getConfig(key));
    }

    /**
     * 根据 key 获取 value
     *
     * @param key key
     * @return value
     */
    public Float getFloat(String key) {
        return TypeUtils.castToFloat(getConfig(key));
    }

    /**
     * 根据 key 获取 value
     *
     * @param key key
     * @return value
     */
    public Double getDouble(String key) {
        return TypeUtils.castToDouble(getConfig(key));
    }

    /**
     * 根据 key 获取 value
     *
     * @param key key
     * @return value
     */
    public BigDecimal getBigDecimal(String key) {
        return TypeUtils.castToBigDecimal(getConfig(key));
    }

    /**
     * 根据 key 获取 value
     *
     * @param key key
     * @return value
     */
    public BigInteger getBigInteger(String key) {
        return TypeUtils.castToBigInteger(getConfig(key));
    }
}
